using System.ComponentModel;
using NUnit.Framework;
using ValidationFramework;

namespace ExampleLibraryCSharp.BusinessBaseClasses
{
	public class NotifyValidatableBaseStringExample
	{
		#region Example
		public class Person : NotifyValidatableBase
		{
			#region Fields

			//Define run-time constants here so UI code has compile-time
			//checks against misspellings in data binding expressions.
			public const string FirstNameMember = "FirstName";
			public const string LastNameMember = "LastName";
			public const string EmailAddressMember = "EmailAddress";
			private string firstName;
			private string lastName;
			private string emailAddress;

			#endregion


			#region Constructor

			public Person()
			{
				PropertyValidationManager.ValidateAll();
			}

			#endregion


			#region Properties

			[RequiredStringRule]
			[LengthStringRule(4)]
			public string FirstName
			{
				get
				{
					return firstName;
				}
				set
				{
					if (firstName != value)
					{
						firstName = value;
						NotifyAndValidate(FirstNameMember);
					}
				}
			}


			[RequiredStringRule]
			[LengthStringRule(50, Minimum = 2)]
			public string LastName
			{
				get
				{
					return lastName;
				}
				set
				{
					if (lastName != value)
					{
						lastName = value;
						NotifyAndValidate(LastNameMember);
					}
				}
			}


			[RequiredStringRule]
			[RegexRule(@"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*",
				ErrorMessage = "Invalid email format.")]
			[LengthStringRule(50)]
			public string EmailAddress
			{
				get
				{
					return emailAddress;
				}
				set
				{
					if (emailAddress != value)
					{
						emailAddress = value;
						NotifyAndValidate(EmailAddressMember);
					}
				}
			}


			#endregion
		}

		[TestFixture]
		public class ExampleUsage
		{
			private bool firstNameEventFired;

			[Test]
			public void RunEvent()
			{
				var person = new Person();

				// Attach to PropertyChanged so we are notified 
				person.PropertyChanged += person_PropertyChanged;

				// Set FirstName and hence firing the event
				person.FirstName = "John";

				// Since the event has fired the firstNameEventFired flag will be true;
				Assert.IsTrue(firstNameEventFired);
			}


			void person_PropertyChanged(object sender, PropertyChangedEventArgs e)
			{
				// Check that it is the property we are interested in
				if (e.PropertyName == Person.FirstNameMember)
				{
					firstNameEventFired = true;
				}
			}


			[Test]
			public void RunIsValid()
			{
				var person = new Person();

				// Initially not valid
				Assert.IsFalse(person.IsValid);

				// Set FirstName, LastName and EmailAddress
				person.FirstName = "John";
				person.LastName = "Smith";
				person.EmailAddress = "John.Smith@email.com";

				// It is now valid
				Assert.IsTrue(person.IsValid);
			}


			[Test]
			public void RunValidatorResultsInError()
			{
				var person = new Person();
				// Initially there should be 3 items in ValidatorResultsInError as only 3 
				// properties have required rules.
				Assert.AreEqual(3, person.ValidatorResultsInError.Count);

				// Set LastName to a value and count goes down to 2
				person.LastName = "Smith";
				// No need to call IsValid (to force a validation) because properties are 
				// validated during each set
				Assert.AreEqual(2, person.ValidatorResultsInError.Count);
			}


			[Test]
			public void RunSpecificProperty()
			{
				var person = new Person();

				// LastName initially has an ErrorMessage because it is invalid
				var lastNameErrorMessage = person[Person.LastNameMember];
				Assert.IsNotNull(lastNameErrorMessage);

				// Set LastName and it will then have no ErrorMessage
				person.LastName = "Smith";
				// No need to call IsValid (to force a validation) because properties are 
				// validated during each set
				lastNameErrorMessage = person[Person.LastNameMember];
				Assert.IsEmpty(lastNameErrorMessage);
			}

		}
		#endregion
	}
}